//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

%import gyb
%TMirrorDecl = gyb.parseTemplate("../../common/MirrorDecl.gyb")
%TMirrorConformance = gyb.parseTemplate("../../common/MirrorConformance.gyb")
%TMirrorBoilerplate = gyb.parseTemplate("../../common/MirrorBoilerplate.gyb")

// helper functions - these Mirrors are dissimilar enough that it's
// probably not worth trying to write one unique generator - let's
// just use these helpers manually and write the bulk of each one
%{
def getMirrorConformance(Self,Disp = None):
  return gyb.executeTemplate(
    TMirrorConformance,introspecteeType=Self,disposition=Disp)

def getMirrorBoilerplate(Self,Disp = None):
  return gyb.executeTemplate(
    TMirrorBoilerplate,introspecteeType=Self,disposition=Disp)

def getMirrorDecl(Self,Disp = None):
  return gyb.executeTemplate(TMirrorDecl,introspecteeType=Self,disposition=Disp)
}%

// actual Mirrors
${getMirrorDecl("NSURL")} {
  ${getMirrorBoilerplate("NSURL")}
  
  var count: Int { get { return 0 } }
  
  subscript(_: Int) -> (String, _MirrorType) {
    _preconditionFailure("_MirrorType access out of bounds")
  }
  
  var summary: String { get { return _value.absoluteString } }
  
  var quickLookObject: PlaygroundQuickLook? { return .Some(.URL(summary)) }
}

${getMirrorDecl("NSRange")} {
  ${getMirrorBoilerplate("NSRange")}
  
  var count: Int { get { return 2 } }
  
  subscript(i: Int) -> (String, _MirrorType) {
    switch i {
    case 0: return ("location", _reflect(_value.location))
    case 1: return ("length", _reflect(_value.length))
    default: _preconditionFailure("_MirrorType access out of bounds")
    }
  }
  
  var summary: String { return "(\(_value.location),\(_value.length))" }
  
  var quickLookObject: PlaygroundQuickLook? {
    return .Some(.Range(Int64(_value.location),Int64(_value.length)))
  }
}

${getMirrorDecl("NSDate")} {
  ${getMirrorBoilerplate("NSDate")}
  
  var count: Int { get { return 0 } }
  
  subscript(i: Int) -> (String, _MirrorType) {
    _preconditionFailure("_MirrorType access out of bounds")
  }
  
  var summary: String {
    let df = NSDateFormatter()
    df.dateStyle = .MediumStyle
    df.timeStyle = .ShortStyle
    return df.stringFromDate(_value)
  }
  
  var quickLookObject: PlaygroundQuickLook? { return .Some(.Text(summary)) }
}

${getMirrorDecl("NSSet","MembershipContainer")} {
  var _a : NSArray!
  var _value: NSSet

  init(_ x: NSSet) {
    _value = x
    _a = _value.allObjects as NSArray
  }
  
  var disposition: _MirrorDisposition { return .MembershipContainer }

  var value: Any { return _value }

  var valueType: Any.Type { return (_value as Any).dynamicType }

  var objectIdentifier: ObjectIdentifier? { return .None }
  
  // this is the only member that needs to validate _a - others either don't touch it or call into this
  var count: Int {
    if _a != nil {
      return _a.count
    }
    return 0
  }
  
  subscript(i: Int) -> (String, _MirrorType) {
    _precondition(i >= 0 && i < count, "_MirrorType access out of bounds")
    return ("[\(i)]", _reflect(_a[i]))
  }
  
  var summary: String { return "\(count) elements" }
  
  var quickLookObject: PlaygroundQuickLook? { return nil }
}

${getMirrorDecl("NSString")} {
  ${getMirrorBoilerplate("NSString")}
  
  var count: Int { get { return 0 } }
  
  subscript(_: Int) -> (String, _MirrorType) {
    _preconditionFailure("_MirrorType access out of bounds")
  }
  
  var summary: String { get { return _value as String } }
  
  var quickLookObject: PlaygroundQuickLook? { return .Some(.Text(summary)) }
}

// conformances
${getMirrorConformance("NSURL")}
${getMirrorConformance("NSRange")}
${getMirrorConformance("NSDate")}
${getMirrorConformance("NSSet","MembershipContainer")}
${getMirrorConformance("NSString")}

extension NSArray : _Reflectable {
  /// Returns a mirror that reflects `self`.
  public func _getMirror() -> _MirrorType {
    return _reflect(self as [AnyObject])
  }
}
extension NSDictionary : _Reflectable {
  /// Returns a mirror that reflects `self`.
  public func _getMirror() -> _MirrorType {
    let dict: [NSObject : AnyObject] = _convertNSDictionaryToDictionary(self)
    return _reflect(dict)
  }
}
